package org.wmq.positiontoshop.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.wmq.positiontoshop.mapper.ShopMapper;
import org.wmq.positiontoshop.model.DO.Shop;
import org.wmq.positiontoshop.service.ElasticsearchSyncService;
import org.wmq.positiontoshop.service.ShopService;

import java.util.List;

/**
 * Shop Service实现类
 * 提供店铺相关的业务逻辑实现
 */
@Service
@Slf4j
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements ShopService {
    
    @Autowired
    private ElasticsearchSyncService elasticsearchSyncService;
    
    /**
     * 保存店铺信息
     * 
     * @param shop 店铺信息
     * @return 保存结果
     */
    @Override
    public boolean save(Shop shop) {
        log.info("保存店铺信息：{}", shop);
        boolean result = super.save(shop);
        
        // 保存成功后同步到Elasticsearch
        if (result && shop.getId() != null) {
            elasticsearchSyncService.syncShopToES(shop.getId());
        }
        
        return result;
    }
    
    /**
     * 更新店铺信息
     * 
     * @param shop 店铺信息
     * @return 更新结果
     */
    @Override
    public boolean updateById(Shop shop) {
        log.info("更新店铺信息：{}", shop);
        boolean result = super.updateById(shop);
        
        // 更新成功后同步到Elasticsearch
        if (result && shop.getId() != null) {
            elasticsearchSyncService.syncShopToES(shop.getId());
        }
        
        return result;
    }
    
    /**
     * 删除店铺信息
     * 
     * @param id 店铺ID
     * @return 删除结果
     */
    public boolean removeById(Long id) {
        log.info("删除店铺信息，id：{}", id);
        boolean result = super.removeById(id);
        
        // 删除成功后从Elasticsearch删除
        if (result) {
            elasticsearchSyncService.deleteShopFromES(id);
        }
        
        return result;
    }
    
    /**
     * 根据经纬度和半径查询附近的店铺
     * 
     * @param longitude 经度
     * @param latitude 纬度
     * @param radius 半径（千米）
     * @return 附近的店铺列表
     */
    @Override
    public List<Shop> getNearbyShops(Double longitude, Double latitude, Double radius) {
        // 使用Haversine公式计算两点间的距离（千米）
        // 这里使用MyBatis-Plus的QueryWrapper实现地理位置查询
        // 注意：在实际项目中，可能需要使用数据库的地理空间索引功能来优化查询性能
        return this.lambdaQuery()
                .apply("6371 * 2 * ASIN(SQRT(POWER(SIN(({0} - latitude) * PI() / 180 / 2), 2) + COS({0} * PI() / 180) * COS(latitude * PI() / 180) * POWER(SIN(({1} - longitude) * PI() / 180 / 2), 2))) < {2}",
                        latitude, longitude, radius)
                .list();
    }
    
    /**
     * 根据店铺类型查询店铺
     * 
     * @param type 店铺类型
     * @return 该类型的店铺列表
     */
    @Override
    public List<Shop> getShopsByType(String type) {
        return this.lambdaQuery()
                .eq(Shop::getType, type)
                .list();
    }
    
    /**
     * 查询营业中的店铺
     * 
     * @return 营业中的店铺列表
     */
    @Override
    public List<Shop> getActiveShops() {
        return this.lambdaQuery()
                .eq(Shop::getStatus, 1) // 1表示营业中
                .list();
    }
    
    /**
     * 根据评分排序查询店铺
     * 
     * @param limit 查询数量
     * @return 按评分排序的店铺列表
     */
    @Override
    public List<Shop> getTopRatedShops(Integer limit) {
        return this.lambdaQuery()
                .orderByDesc(Shop::getRating)
                .last("LIMIT " + limit)
                .list();
    }

    @Override
    public boolean addScore(Long id, long score) {
        return this.lambdaUpdate().eq(Shop::getId, id).
                setSql(score >= 0, "score = score + " + score).update();
    }

    /**
     * 根据经纬度和半径，获得score前五的商家
     * 
     * @param langtitude 经度
     * @param latitude 纬度
     * @param radius 半径（千米）
     * @return score前五的商家列表
     */
    @Override
    public List<Shop> getTop5ByScore(Double langtitude, Double latitude, Double radius) {
        log.info("查询经纬度附近score前五的商家，经度：{}, 纬度：{}, 半径：{}千米", langtitude, latitude, radius);
        
        // 使用Haversine公式计算两点间的距离（千米），筛选出半径内的店铺
        // 然后按score字段降序排序，取前5条记录
        return this.lambdaQuery()
                .apply("6371 * 2 * ASIN(SQRT(POWER(SIN(({0} - latitude) * PI() / 180 / 2), 2) + COS({0} * PI() / 180) * COS(latitude * PI() / 180) * POWER(SIN(({1} - longitude) * PI() / 180 / 2), 2))) < {2}",
                        latitude, langtitude, radius)
                .orderByDesc(Shop::getScore)
                .last("LIMIT 5")
                .list();
    }
}